<!doctype html>



  


<html class="theme-next pisces use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>



<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.0" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="前端,webpack,react,karma,mocha,sinon," />








  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.0" />






<meta name="description" content="前言Update
[20160725] Facebook 官方提供了一个可以生成React Starter项目的工具，有兴趣可以看下：create-react-app

React技术之火爆无须多言，其与webpack的完美结合，也让二者毋庸置疑的成为天生一对。为了进行React的快速和规范化开发，开源社区中涌现了很多React+webpack的boilerplate项目。通过使用这些boiler">
<meta property="og:type" content="article">
<meta property="og:title" content="手把手教你基于ES6架构自己的React Boilerplate项目">
<meta property="og:url" content="http://jiji262.github.io/2016/04/29/create-your-own-react-boilerplate/index.html">
<meta property="og:site_name" content="令狐葱@前端笔记">
<meta property="og:description" content="前言Update
[20160725] Facebook 官方提供了一个可以生成React Starter项目的工具，有兴趣可以看下：create-react-app

React技术之火爆无须多言，其与webpack的完美结合，也让二者毋庸置疑的成为天生一对。为了进行React的快速和规范化开发，开源社区中涌现了很多React+webpack的boilerplate项目。通过使用这些boiler">
<meta property="og:image" content="http://webpack.github.io/assets/what-is-webpack.png">
<meta property="og:image" content="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fq4VS1Pe2NGaTyUIkNKJCADwE-iy336.jpg">
<meta property="og:image" content="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fg7Cmp52pR7rdmvgdzobkVRGD2d_524.jpg">
<meta property="og:image" content="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fp02wNcFcOPzZwNHB0QndYcFZ6b8336.jpg">
<meta property="og:image" content="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fr2AQN-7eCUyPuWVoFQBiVuiSmEU814.jpg">
<meta property="og:image" content="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/FhsJFMi-612vNsHQhDgwt8abvfKB814.jpg">
<meta property="og:image" content="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/FryFP8lTIrAosvDBBFT5h5nznmuH814.jpg">
<meta property="og:image" content="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fo8y7n8p4qhOi9Bq0gf3pXE-xrJQ87.jpg">
<meta property="og:updated_time" content="2017-02-22T02:12:37.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="手把手教你基于ES6架构自己的React Boilerplate项目">
<meta name="twitter:description" content="前言Update
[20160725] Facebook 官方提供了一个可以生成React Starter项目的工具，有兴趣可以看下：create-react-app

React技术之火爆无须多言，其与webpack的完美结合，也让二者毋庸置疑的成为天生一对。为了进行React的快速和规范化开发，开源社区中涌现了很多React+webpack的boilerplate项目。通过使用这些boiler">
<meta name="twitter:image" content="http://webpack.github.io/assets/what-is-webpack.png">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    sidebar: {"position":"post","display":"post"},
    fancybox: true,
    motion: true,
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://jiji262.github.io/2016/04/29/create-your-own-react-boilerplate/"/>





  <title> 手把手教你基于ES6架构自己的React Boilerplate项目 | 令狐葱@前端笔记 </title>
</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  





  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?0fd825270d7f51597f963010828c65b8";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>










  
  
    
  

  <div class="container one-collumn sidebar-position-post page-post-detail ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-meta ">
  

  <div class="custom-logo-site-title">
    <a href="/"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">令狐葱@前端笔记</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
    
      <p class="site-subtitle"></p>
    
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://jiji262.github.io/2016/04/29/create-your-own-react-boilerplate/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="令狐葱">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="令狐葱@前端笔记">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="令狐葱@前端笔记" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                手把手教你基于ES6架构自己的React Boilerplate项目
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2016-04-29T20:10:00+08:00">
                2016-04-29
              </time>
            

            

            
          </span>

          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2016/04/29/create-your-own-react-boilerplate/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2016/04/29/create-your-own-react-boilerplate/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><h2 id="Update"><a href="#Update" class="headerlink" title="Update"></a><strong>Update</strong></h2><ul>
<li>[20160725] Facebook 官方提供了一个可以生成React Starter项目的工具，有兴趣可以看下：<a href="https://github.com/facebookincubator/create-react-app" target="_blank" rel="external">create-react-app</a></li>
</ul>
<p><code>React</code>技术之火爆无须多言，其与<code>webpack</code>的完美结合，也让二者毋庸置疑的成为天生一对。为了进行<code>React</code>的快速和规范化开发，开源社区中涌现了很多<code>React</code>+<code>webpack</code>的<code>boilerplate</code>项目。通过使用这些<code>boilerplate</code>，我们可以快速的创建一个React项目的架构。</p>
<p><a href="https://github.com/jiji262" target="_blank" rel="external">葱哥</a>之前专门创建了一个Github项目用于收集这些<code>boilerplate</code>：<a href="http://jiji262.github.io/awesome-react-boilerplate/">awesome-react-boilerplate</a>。当然这里不可能完整收录，但是目前为止已经有近30个了。连boilerplate都这么多，真让我们眼花缭乱，无从下手。</p>
<p>当然，由于每个人的使用习惯和技术背景的不同，每个<code>boilerplate</code>都会有自己的侧重点，因此即便是公认比较好的boilerplate项目也未必适合所有人。我们拿到这些开源项目，只是知其然但是并不知其所以然。<a href="https://github.com/jiji262" target="_blank" rel="external">葱哥</a>相信，只有适合自己的，才是最好的。这就是本文的初衷，<a href="https://github.com/jiji262" target="_blank" rel="external">葱哥</a>会追根溯源，从项目开发的蛮荒阶段开始，搭建开发环境，配置<code>webpack</code>，在<code>React</code>项目中使用<code>webpack</code>，搭建项目的测试环境，一步一步构建适合适合自己的<code>React</code> + <code>webpack</code>起始项目。</p>
<p>本文陆陆续续写了将近一个月的时间，所使用的技术和依赖库均选用目前最新版本，其间大大小小的坑踩过不知道多少。本文供入门参考，如果你是前端大牛，请直接忽略此文。</p>
<p>当然，如果读后觉得对你有帮助，还请关注<a href="https://github.com/jiji262" target="_blank" rel="external">葱哥的Github</a>。</p>
<p>TL;DR</p>
<h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p>本文所有代码可以在我的Github中找到：</p>
<p><a href="https://github.com/jiji262/react_boilerplate" target="_blank" rel="external">react_boilerplate</a></p>
<h2 id="将使用的技术栈"><a href="#将使用的技术栈" class="headerlink" title="将使用的技术栈"></a>将使用的技术栈</h2><p>如前所述，本文的主要目的是构建适合适合自己的<code>React</code> + <code>webpack</code>起始项目。与其他多数类似项目不同的是，我们不仅要支持ES6，使用webpack，而且要搭建一套相对完整的单元测试和自动化测试体系。本文主要使用到的相关技术如下：</p>
<ul>
<li>React</li>
<li>webpack</li>
<li>babel</li>
<li>ES6</li>
<li>mocha</li>
<li>chai</li>
<li>sinon</li>
<li>karma</li>
<li>phantomJS</li>
</ul>
<a id="more"></a>
<h1 id="webpack快速入门"><a href="#webpack快速入门" class="headerlink" title="webpack快速入门"></a>webpack快速入门</h1><h2 id="webpack介绍"><a href="#webpack介绍" class="headerlink" title="webpack介绍"></a>webpack介绍</h2><p>Webpack是一个前端模块管理工具，有点类似browserify，出自Facebook的Instagram团队，但功能比browserify更为强大，可以说是目前最为强大的前端模块管理和打包工具。</p>
<p>Webpack将项目中的所有静态资源都当做模块，模块之间可以互相依赖，由webpack对它们进行统一的管理和打包发布，下图为官方网站说明：</p>
<p><img src="http://webpack.github.io/assets/what-is-webpack.png" alt="web pack"></p>
<p>webpack对React有着与生俱来的良好支持，随着React的流行，webpack也成了React项目中必不可少的一部分。特别是随着ES6的普及，使得webpack有了更广阔的用武之地。</p>
<h2 id="安装配置webpack"><a href="#安装配置webpack" class="headerlink" title="安装配置webpack"></a>安装配置webpack</h2><h3 id="安装nodejs"><a href="#安装nodejs" class="headerlink" title="安装nodejs"></a>安装nodejs</h3><p>安装webpack之前，需要确认本机已经安装好了nodejs。</p>
<p>如果还没有安装，请去<a href="https://nodejs.org" target="_blank" rel="external">nodejs官网</a>下载安装即可。这里使用的node版本是V4.4.1.</p>
<h3 id="初始化项目环境"><a href="#初始化项目环境" class="headerlink" title="初始化项目环境"></a>初始化项目环境</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">$ mkdir react_boilerplate</div><div class="line">$ <span class="built_in">cd</span> react_boilerplate\</div><div class="line"></div><div class="line">$ npm init -y</div><div class="line">Wrote to .\react_boilerplate\package.json:</div><div class="line"></div><div class="line">&#123;</div><div class="line">  <span class="string">"name"</span>: <span class="string">"react_boilerplate"</span>,</div><div class="line">  <span class="string">"version"</span>: <span class="string">"1.0.0"</span>,</div><div class="line">  <span class="string">"description"</span>: <span class="string">""</span>,</div><div class="line">  <span class="string">"main"</span>: <span class="string">"index.js"</span>,</div><div class="line">  <span class="string">"scripts"</span>: &#123;</div><div class="line">    <span class="string">"test"</span>: <span class="string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span></div><div class="line">  &#125;,</div><div class="line">  <span class="string">"keywords"</span>: [],</div><div class="line">  <span class="string">"author"</span>: <span class="string">""</span>,</div><div class="line">  <span class="string">"license"</span>: <span class="string">"ISC"</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>npm init</code> 加上一个<code>-y</code>选项会生成一个默认的<code>package.json</code>,关于这个文件，不是本文重点，在此不会详述，可以参考<a href="https://docs.npmjs.com/files/package.json" target="_blank" rel="external">官方文档</a>。可以简单的理解，这个文件是用于管理项目里面的依赖包的。</p>
<h3 id="设置-gitignore"><a href="#设置-gitignore" class="headerlink" title="设置.gitignore"></a>设置.gitignore</h3><p>如果我们使用git进行版本管理，一个.gitignore文件是必要的。这里我们可以先将项目需要安装的node包目录添加进去。</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">node_modules</div></pre></td></tr></table></figure>
<p>使用<code>npm install</code>安装的node包都会在<code>node_modules</code>目录下，这个目录是不需要commit到git的。</p>
<h3 id="安装webpack"><a href="#安装webpack" class="headerlink" title="安装webpack"></a>安装webpack</h3><p>安装webpack很简单，命令如下：</p>
<figure class="highlight q"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm i webpack --<span class="built_in">save</span>-<span class="built_in">dev</span></div></pre></td></tr></table></figure>
<p>其中<code>--save-dev</code>表示该包为开发环境依赖包。安装完后会生成一个<code>node_modules</code>目录，并且在<code>package.json</code>文件中多出如下几行：</p>
<figure class="highlight lasso"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="attr">...</span><span class="attr">...</span></div><div class="line">  <span class="string">"devDependencies"</span>: &#123;</div><div class="line">    <span class="string">"webpack"</span>: <span class="string">"^1.13.0"</span></div><div class="line">  &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>如果写为<code>--save</code>则表示该包为生产环境依赖包，在<code>package.json</code>文件中会新增或者修改<code>dependencies</code> 字段。</p>
<h3 id="初始化项目结构和代码"><a href="#初始化项目结构和代码" class="headerlink" title="初始化项目结构和代码"></a>初始化项目结构和代码</h3><p>安装完<code>webpack</code>后，我们可以给项目中增加一些内容了。项目的简单结构如下图所示：</p>
<p><img src="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fq4VS1Pe2NGaTyUIkNKJCADwE-iy336.jpg" alt="目录结构"></p>
<p><code>app</code>目录用于存放项目代码，<code>dist</code>目录为编译后的项目文件，<code>webpack.config.js</code>为<code>webpack</code>的配置文件。</p>
<p>我们给项目中的文件添加一些简单的代码，首先是组件代码：</p>
<h4 id="app-component-js"><a href="#app-component-js" class="headerlink" title="app/component.js"></a>app/component.js</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> element = <span class="built_in">document</span>.createElement(<span class="string">'h1'</span>);</div><div class="line"></div><div class="line">  element.innerHTML = <span class="string">'Hello world'</span>;</div><div class="line"></div><div class="line">  <span class="keyword">return</span> element;</div><div class="line">&#125;;</div></pre></td></tr></table></figure>
<p>然后需要一个入口文件，在入口文件中使用上面定义的组件：</p>
<h4 id="app-index-js"><a href="#app-index-js" class="headerlink" title="app/index.js"></a>app/index.js</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> component = <span class="built_in">require</span>(<span class="string">'./component'</span>);</div><div class="line"></div><div class="line"><span class="built_in">document</span>.body.appendChild(component());</div></pre></td></tr></table></figure>
<h3 id="配置webpack"><a href="#配置webpack" class="headerlink" title="配置webpack"></a>配置webpack</h3><p>我们需要让webpack知道如何处理我们的项目目录结构，因此需要配置文件<code>webpack.config.js</code>。一个简单的配置文件如下所示：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> webpack = <span class="built_in">require</span>(<span class="string">'webpack'</span>); </div><div class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);                 <span class="comment">//引入node的path库</span></div><div class="line"></div><div class="line"><span class="keyword">var</span> config = &#123;</div><div class="line">  entry: [<span class="string">'./app/index.js'</span>],                <span class="comment">//入口文件</span></div><div class="line">  output: &#123;</div><div class="line">    path: path.resolve(__dirname, <span class="string">'dist'</span>),  <span class="comment">// 指定编译后的代码位置为 dist/bundle.js</span></div><div class="line">    filename: <span class="string">'bundle.js'</span></div><div class="line">  &#125;,</div><div class="line">  <span class="built_in">module</span>: &#123;</div><div class="line">    loaders: [</div><div class="line">      <span class="comment">// 为webpack指定loaders</span></div><div class="line">      <span class="comment">//&#123; test: /\.js$/, loaders: ['babel'], exclude: /node_modules/ &#125;   </span></div><div class="line">    ]</div><div class="line">  &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="built_in">module</span>.exports = config;</div></pre></td></tr></table></figure>
<p>到目前为止，我们已经可以让webpack工作了，在命令行执行</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">webpack</div></pre></td></tr></table></figure>
<p>我们看到，会有一个新的文件<code>/dist/bundle.js</code>生成出来了。但是我们还需要一个html文件来加载编译后的代码，这就需要用到一个webpack插件：<code>html-webpack-plugin</code>。</p>
<h3 id="安装html-webpack-plugin"><a href="#安装html-webpack-plugin" class="headerlink" title="安装html-webpack-plugin"></a>安装<code>html-webpack-plugin</code></h3><p>使用如下命令安装：</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm <span class="keyword">install</span> html-webpack-<span class="keyword">plugin</span> <span class="comment">--save-dev</span></div></pre></td></tr></table></figure>
<p>然后在我们的<code>webpack.config.js</code>中增加下面几行：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">plugins: [</div><div class="line">  <span class="keyword">new</span> HtmlwebpackPlugin(&#123;</div><div class="line">    title: <span class="string">'React Biolerplate by Linghucong'</span></div><div class="line">  &#125;)</div><div class="line">]</div></pre></td></tr></table></figure></p>
<p>现在在命令行下再次执行<code>webpack</code>命令，会看到在<code>dist</code>目录下生成了两个文件：<code>bundle.js</code>和<code>index.html</code>。其中<code>index.html</code>内容如下：</p>
<h4 id="dist-index-html"><a href="#dist-index-html" class="headerlink" title="dist/index.html"></a>dist/index.html</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>React Biolerplate by Linghucong<span class="tag">&lt;/<span class="name">title</span>&gt;</span></div><div class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></div><div class="line">  <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"bundle.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span><span class="tag">&lt;/<span class="name">body</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></div></pre></td></tr></table></figure>
<p>有必要提一下，如果我们安装webpack的时候使用的是全局安装选项（<code>npm install -g webpack</code>），可以在命令行中直接执行<code>webpack</code>命令；如果没有使用<code>-g</code>，那么要用的<code>webpack</code>可执行文件位于：<br><figure class="highlight coffeescript"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">.<span class="regexp">/node_modules/</span>.bin/webpack</div></pre></td></tr></table></figure></p>
<p>我们可以在<code>package.json</code>中为此命令增加一个快捷方式：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">// package.json</div><div class="line">... other stuff</div><div class="line"><span class="string">"scripts"</span>: &#123;</div><div class="line">  <span class="string">"build"</span>: <span class="string">"./node_modules/.bin/webpack"</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>现在就可以直接使用命令<code>npm run build</code>来执行webpack了。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">$ npm run build</div><div class="line"></div><div class="line">&gt; react_boilerplate@<span class="number">1.0</span><span class="number">.0</span> build D:\node\react_boilerplate</div><div class="line">&gt; webpack</div><div class="line"></div><div class="line">Hash: cbf754a65493b4d791d7</div><div class="line">Version: webpack <span class="number">1.13</span><span class="number">.0</span></div><div class="line">Time: <span class="number">919</span>ms</div><div class="line">     Asset       Size  Chunks             Chunk Names</div><div class="line"> bundle.js     <span class="number">233</span> kB       <span class="number">0</span>  [emitted]  main</div><div class="line">index.html  <span class="number">179</span> bytes          [emitted]</div><div class="line">   [<span class="number">0</span>] multi main <span class="number">52</span> bytes &#123;<span class="number">0</span>&#125; [built]</div><div class="line">  [<span class="number">75</span>] ./app/index.js <span class="number">82</span> bytes &#123;<span class="number">0</span>&#125; [built]</div><div class="line">  [<span class="number">76</span>] ./app/component.js <span class="number">142</span> bytes &#123;<span class="number">0</span>&#125; [built]</div><div class="line">    + <span class="number">74</span> hidden modules</div><div class="line">Child html-webpack-plugin <span class="keyword">for</span> <span class="string">"index.html"</span>:</div><div class="line">        + <span class="number">3</span> hidden modules</div></pre></td></tr></table></figure>
<h3 id="安装webpack-dev-server"><a href="#安装webpack-dev-server" class="headerlink" title="安装webpack-dev-server"></a>安装<code>webpack-dev-server</code></h3><p><code>webpack-dev-server</code>可以让我们在本地启动一个web服务器，使我们更方便的查看正在开发的项目。其安装也十分简单：</p>
<figure class="highlight q"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm i webpack-<span class="built_in">dev</span>-server --<span class="built_in">save</span>-<span class="built_in">dev</span></div></pre></td></tr></table></figure>
<p>然后在<code>webpack.config.js</code>文件中作如下修改：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// webpack.config.js</span></div><div class="line"><span class="comment">// ...</span></div><div class="line">  entry: [</div><div class="line">    <span class="string">'webpack/hot/dev-server'</span>,</div><div class="line">    <span class="string">'webpack-dev-server/client?http://localhost:3000'</span>,</div><div class="line">    <span class="string">'./app/index.js'</span>      <span class="comment">//入口文件</span></div><div class="line">    ],  </div><div class="line"><span class="comment">// ...</span></div></pre></td></tr></table></figure></p>
<p>我们可以在<code>package.json</code>中增加<code>webpack-dev-server</code>的快捷方式：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// package.json</span></div><div class="line">... other stuff</div><div class="line"><span class="string">"scripts"</span>: &#123;</div><div class="line">  <span class="string">"dev"</span>: <span class="string">"webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist"</span>,</div><div class="line">  <span class="string">"build"</span>: <span class="string">"./node_modules/.bin/webpack"</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>配置中指定web服务器端口号为3000，指定目录为dist。<br>运行<code>npm run dev</code>：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">$ npm run dev</div><div class="line"></div><div class="line">&gt; react_boilerplate@<span class="number">1.0</span><span class="number">.0</span> dev D:\node\react_boilerplate</div><div class="line">&gt; webpack-dev-server --port <span class="number">3000</span> --devtool <span class="built_in">eval</span> --progress --colors --hot --content-base dist</div><div class="line"></div><div class="line">......</div><div class="line">Time: <span class="number">1109</span>ms</div><div class="line">     Asset       Size  Chunks             Chunk Names</div><div class="line"> bundle.js     <span class="number">274</span> kB       <span class="number">0</span>  [emitted]  main</div><div class="line">index.html  <span class="number">179</span> bytes          [emitted]</div><div class="line">chunk    &#123;<span class="number">0</span>&#125; bundle.js (main) <span class="number">216</span> kB [rendered]</div><div class="line">    [<span class="number">0</span>] multi main <span class="number">52</span> bytes &#123;<span class="number">0</span>&#125; [built]</div><div class="line"> ......</div><div class="line"> ......</div><div class="line"> ......</div><div class="line">   [<span class="number">77</span>] ./app/component.js <span class="number">142</span> bytes &#123;<span class="number">0</span>&#125; [built]</div><div class="line">Child html-webpack-plugin <span class="keyword">for</span> <span class="string">"index.html"</span>:</div><div class="line">    chunk    &#123;<span class="number">0</span>&#125; index.html <span class="number">505</span> kB [rendered]</div><div class="line">        [<span class="number">0</span>] ./~<span class="regexp">/html-webpack-plugin/</span>lib/loader.js!./~<span class="regexp">/html-webpack-plugin/</span>default_index.ejs <span class="number">540</span> bytes &#123;<span class="number">0</span>&#125; [buil</div><div class="line">t]</div><div class="line">        [<span class="number">1</span>] ./~<span class="regexp">/lodash/</span>lodash.js <span class="number">504</span> kB &#123;<span class="number">0</span>&#125; [built]</div><div class="line">        [<span class="number">2</span>] (webpack)/buildin/<span class="built_in">module</span>.js <span class="number">251</span> bytes &#123;<span class="number">0</span>&#125; [built]</div><div class="line">webpack: bundle is now VALID.</div></pre></td></tr></table></figure></p>
<p>web服务器启动完毕，此时访问 <a href="http://localhost:3000/" target="_blank" rel="external">http://localhost:3000/</a> 就可以看到我们的“Hello world”了。<br><img src="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fg7Cmp52pR7rdmvgdzobkVRGD2d_524.jpg" alt="hello world"></p>
<p>需要特别说明的是，<code>webpack-dev-server</code>是支持热加载的，也就是说我们对代码的改动，保存的时候会自动更新页面。比如我们在文件中将“Hello world”改为“Linghucong”，会看到页面实时更新了，无须再按F5刷新，爽吧？！<br><img src="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fp02wNcFcOPzZwNHB0QndYcFZ6b8336.jpg" alt="linghucong"></p>
<p><code>webpack-dev-server</code>的配置还可以放在<code>webpack.config.js</code>中，需要使用一个<code>devServer</code>属性，详细可以<a href="https://webpack.github.io/docs/webpack-dev-server.html" target="_blank" rel="external">参考官方文档</a>。</p>
<h3 id="处理CSS样式"><a href="#处理CSS样式" class="headerlink" title="处理CSS样式"></a>处理CSS样式</h3><p>项目中使用CSS是必不可少的。webpack中使用<br>loader的方式来处理各种各样的资源，根据设定的规则，会找到相应的文件路径，然后使用各自的loader来处理。CSS文件也需要特定的loader，一般需要使用两个：<code>css-loader</code>和 <code>style-loader</code>，如果使用LESS或者SASS还需要加载对应的loader。这里我们使用LESS，因此安装loaders:</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm <span class="keyword">install</span> css-loader <span class="keyword">style</span>-loader <span class="keyword">less</span>-loader <span class="comment">--save-dev</span></div></pre></td></tr></table></figure>
<h4 id="踩坑提醒"><a href="#踩坑提醒" class="headerlink" title="踩坑提醒"></a>踩坑提醒</h4><p>npm3.0以上需要单独安装less：<code>npm install less --save-dev</code>。</p>
<p>然后在文件<code>webpack.config.js</code>中配置：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line">  test: <span class="regexp">/\.less$/</span>,</div><div class="line">  loaders: [<span class="string">'style'</span>, <span class="string">'css'</span>, <span class="string">'less'</span>],</div><div class="line">  include: path.resolve(__dirname, <span class="string">'app'</span>)</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>可以看到，test里面包含一个正则，包含需要匹配的文件，loaders是一个数组，包含要处理这些文件的loaders，注意loaders的执行顺序是从右到左的。</p>
<p>新建一个LESS文件<code>/app/index.less</code>，其内容如下：<br><figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="selector-tag">h1</span> &#123;</div><div class="line">    <span class="attribute">color</span>: green;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>在入口文件<code>index.js</code>中引入这个文件：<br><figure class="highlight coffeescript"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">require</span>(<span class="string">'./index.less'</span>);</div></pre></td></tr></table></figure></p>
<p>然后运行webpack进行编译：<code>npm run build</code>:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">$ npm run build</div><div class="line"></div><div class="line">&gt; react_boilerplate@<span class="number">1.0</span><span class="number">.0</span> build D:\node\react_boilerplate</div><div class="line">&gt; webpack</div><div class="line"></div><div class="line">Hash: <span class="number">0</span>c25c4bacdc334db1e04</div><div class="line">Version: webpack <span class="number">1.13</span><span class="number">.0</span></div><div class="line">Time: <span class="number">1902</span>ms</div><div class="line">     Asset       Size  Chunks             Chunk Names</div><div class="line"> bundle.js     <span class="number">243</span> kB       <span class="number">0</span>  [emitted]  main</div><div class="line">index.html  <span class="number">179</span> bytes          [emitted]</div><div class="line">   [<span class="number">0</span>] multi main <span class="number">52</span> bytes &#123;<span class="number">0</span>&#125; [built]</div><div class="line">  [<span class="number">75</span>] ./app/index.js <span class="number">110</span> bytes &#123;<span class="number">0</span>&#125; [built]</div><div class="line">  [<span class="number">80</span>] ./app/component.js <span class="number">141</span> bytes &#123;<span class="number">0</span>&#125; [built]</div><div class="line">    + <span class="number">78</span> hidden modules</div><div class="line">Child html-webpack-plugin <span class="keyword">for</span> <span class="string">"index.html"</span>:</div><div class="line">        + <span class="number">3</span> hidden modules</div></pre></td></tr></table></figure></p>
<p>可以看到， <a href="http://localhost:3000/" target="_blank" rel="external">http://localhost:3000/</a> 页面上的文字已经变成绿色了。<br><img src="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fr2AQN-7eCUyPuWVoFQBiVuiSmEU814.jpg" alt="green"></p>
<p>到目前为止的代码可以在<a href="https://github.com/jiji262/react_boilerplate/tree/master/_tutorial_/react_boilerplate_v1" target="_blank" rel="external">react_boilerplate _v1</a>中查看。</p>
<h2 id="webpack-支持ES6"><a href="#webpack-支持ES6" class="headerlink" title="webpack 支持ES6"></a>webpack 支持ES6</h2><h3 id="Javascript包管理格式"><a href="#Javascript包管理格式" class="headerlink" title="Javascript包管理格式"></a>Javascript包管理格式</h3><p>Javascript中的包管理比较常见的有几种方式：</p>
<h4 id="CommonJS"><a href="#CommonJS" class="headerlink" title="CommonJS"></a>CommonJS</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//CommonJS 定义的是模块的同步加载，主要用于NodeJS</span></div><div class="line"></div><div class="line"><span class="keyword">var</span> MyModule = <span class="built_in">require</span>(<span class="string">'./MyModule'</span>);</div><div class="line"></div><div class="line"><span class="comment">// export at module root</span></div><div class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; ... &#125;;</div><div class="line"></div><div class="line"><span class="comment">// alternatively, export individual functions</span></div><div class="line">exports.hello = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;...&#125;;</div></pre></td></tr></table></figure>
<h4 id="AMD"><a href="#AMD" class="headerlink" title="AMD"></a>AMD</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//AMD 是异步加载，比如require.js使用这种规范</span></div><div class="line">define([<span class="string">'./MyModule.js'</span>], <span class="function"><span class="keyword">function</span> (<span class="params">MyModule</span>) </span>&#123;</div><div class="line">  <span class="comment">// export at module root</span></div><div class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;&#125;;</div><div class="line">&#125;);</div><div class="line"></div><div class="line"><span class="comment">// or</span></div><div class="line">define([<span class="string">'./MyModule.js'</span>], <span class="function"><span class="keyword">function</span> (<span class="params">MyModule</span>) </span>&#123;</div><div class="line">  <span class="comment">// export as module function</span></div><div class="line">  <span class="keyword">return</span> &#123;</div><div class="line">    hello: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;...&#125;</div><div class="line">  &#125;;</div><div class="line">&#125;);</div></pre></td></tr></table></figure>
<h4 id="ES6"><a href="#ES6" class="headerlink" title="ES6"></a>ES6</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//ES6 变得越来越主流了</span></div><div class="line"></div><div class="line"><span class="keyword">import</span> MyModule <span class="keyword">from</span> <span class="string">'./MyModule.js'</span>;</div><div class="line"></div><div class="line"><span class="comment">// export at module root</span></div><div class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123; ... &#125;;</div><div class="line"></div><div class="line"><span class="comment">// or export as module function,</span></div><div class="line"><span class="comment">// you can have multiple of these per module</span></div><div class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">hello</span>(<span class="params"></span>) </span>&#123;...&#125;;</div></pre></td></tr></table></figure>
<p>还有其他格式如UMD、CMD等，在此不再一一介绍。webpack对这些模块格式都可以很好的支持。在我们之前的项目中使用的是CommonJS格式的模块管理，但是随着ES6的普及和应用，同时得益于强大的<a href="https://babeljs.io/" target="_blank" rel="external">Babel</a>的存在，使我们可以方便的使用ES6的语法，而不必考虑浏览器支持的问题。</p>
<h3 id="webpack支持ES6语法"><a href="#webpack支持ES6语法" class="headerlink" title="webpack支持ES6语法"></a>webpack支持ES6语法</h3><p>在webpack中支持ES6同样只需要安装配置相应的loader就可以了。</p>
<p>安装如下：</p>
<figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm <span class="keyword">install </span><span class="keyword">babel-loader </span><span class="keyword">babel-core </span><span class="keyword">babel-preset-es2015 </span><span class="keyword">babel-preset-react </span>--save-dev</div></pre></td></tr></table></figure>
<p>在<code>webpack.config.js</code>中添加loader如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">&#123; </div><div class="line">  test: <span class="regexp">/\.jsx?$/</span>, </div><div class="line">  loader: <span class="string">'babel'</span>, </div><div class="line">  exclude: <span class="regexp">/node_modules/</span>,</div><div class="line">  query: &#123;</div><div class="line">    presets: [<span class="string">'react'</span>, <span class="string">'es2015'</span>] </div><div class="line">  &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>由于后边需要支持React的jsx文件，所以我们在这里安装了<code>babel-preset-react</code>。</p>
<p>顺便提一下，我们可以在项目根目录下创建一个<code>.babelrc</code>文件，将loader中的<code>presets</code>放在文件<code>.babelrc</code>中：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// .babelrc</span></div><div class="line">&#123;</div><div class="line">  <span class="string">"presets"</span>: [<span class="string">"react"</span>, <span class="string">"es2015"</span>]</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>此时我们运行<code>npm run build</code>，正常编译后，使用<code>npm run dev</code>，启动web服务器，打开 <a href="http://localhost:3000/" target="_blank" rel="external">http://localhost:3000/</a> 可以看到页面已经可以正常显示了。</p>
<h4 id="踩坑提醒-1"><a href="#踩坑提醒-1" class="headerlink" title="踩坑提醒"></a>踩坑提醒</h4><p>如果上面对于loader的配置写为（注意这里是<code>loaders</code>不是<code>loader</code>）：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">&#123; </div><div class="line">    test: <span class="regexp">/\.jsx?$/</span>, </div><div class="line">    loaders: [<span class="string">'babel'</span>], </div><div class="line">    exclude: <span class="regexp">/node_modules/</span>,</div><div class="line">    query: &#123;</div><div class="line">      presets: [<span class="string">'es2015'</span>, <span class="string">'react'</span>] </div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>则可能会出现这样的错误：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">$ npm run build</div><div class="line"></div><div class="line">&gt; react_boilerplate@<span class="number">1.0</span><span class="number">.0</span> build D:\node\react_boilerplate</div><div class="line">&gt; webpack</div><div class="line"></div><div class="line">D:\node\react_boilerplate\node_modules\webpack-core\lib\LoadersList.js:<span class="number">54</span></div><div class="line">                <span class="keyword">if</span>(!element.loader || element.loader.indexOf(<span class="string">"!"</span>) &gt;= <span class="number">0</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">"Cannot define 'query' and multiple loaders in loaders list"</span>);</div><div class="line">                                                                        ^</div><div class="line"></div><div class="line"><span class="built_in">Error</span>: Cannot define <span class="string">'query'</span> and multiple loaders <span class="keyword">in</span> loaders list</div><div class="line">    at getLoadersFromObject (D:\node\react_boilerplate\node_modules\webpack-core\lib\LoadersList.js:<span class="number">54</span>:<span class="number">65</span>)</div><div class="line">    at LoadersList. (D:\node\react_boilerplate\node_modules\webpack-core\lib\LoadersList.js:<span class="number">78</span>:<span class="number">12</span>)</div><div class="line">    at <span class="built_in">Array</span>.map (native)</div><div class="line">    at LoadersList.match </div><div class="line">    ...</div></pre></td></tr></table></figure></p>
<p>原因是使用了多个<code>loader</code>，而<code>query</code>仅仅作用于<code>babel-loader</code>。如果非要使用<code>loaders</code>加载多个<code>loader</code>，可以做如下修改：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> babelPresets = &#123;presets: [<span class="string">'react'</span>, <span class="string">'es2015'</span>]&#125;;</div><div class="line">......</div><div class="line">loaders: [<span class="string">'other-loader'</span>, <span class="string">'babel-loader?'</span>+<span class="built_in">JSON</span>.stringify(babelPresets)]</div><div class="line">......</div></pre></td></tr></table></figure></p>
<p>到目前为止的代码可以在<a href="https://github.com/jiji262/react_boilerplate/tree/master/_tutorial_/react_boilerplate_v2" target="_blank" rel="external">react_boilerplate _v2</a>中查看。</p>
<h1 id="在项目中支持使用React"><a href="#在项目中支持使用React" class="headerlink" title="在项目中支持使用React"></a>在项目中支持使用React</h1><p>关于React的介绍和基本概念相信你已经有所了解，如果需要，可以参考本文最后的“参考阅读”中的链接，在此不再详述。</p>
<h2 id="安装React"><a href="#安装React" class="headerlink" title="安装React"></a>安装React</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm <span class="keyword">install</span> react react-dom <span class="comment">--save</span></div></pre></td></tr></table></figure>
<p>这里我们使用的版本是15.0.1。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">$ npm install react react-dom --save</div><div class="line">react_boilerplate@<span class="number">1.0</span><span class="number">.0</span> D:\node\react_boilerplate</div><div class="line">+-- react@<span class="number">15.0</span><span class="number">.1</span></div><div class="line">| <span class="string">`-- fbjs@0.8.1</span></div><div class="line">|   +-- isomorphic-fetch@2.2.1</div><div class="line">|   | +-- node-fetch@1.5.1</div><div class="line">|   | | +-- encoding@0.1.12</div><div class="line">|   | | | `-- iconv-lite@<span class="number">0.4</span><span class="number">.13</span></div><div class="line">|   | | <span class="string">`-- is-stream@1.1.0</span></div><div class="line">|   | `-- whatwg-fetch@<span class="number">0.11</span><span class="number">.0</span></div><div class="line">|   <span class="string">`-- ua-parser-js@0.7.10</span></div><div class="line">`-- react-dom@<span class="number">15.0</span><span class="number">.1</span></div></pre></td></tr></table></figure></p>
<h2 id="改造项目结构"><a href="#改造项目结构" class="headerlink" title="改造项目结构"></a>改造项目结构</h2><p>在项目中我们使用了html-webpack-plugin插件来用webpack自动生成入口的index.html文件，但是里面的内容我们没法控制。html-webpack-plugin提供了一种模板的机制，可以让我们对生成的文件内容进行定制。</p>
<h3 id="创建模板文件"><a href="#创建模板文件" class="headerlink" title="创建模板文件"></a>创建模板文件</h3><p>我们使用一个新的目录templates用于存放模板文件，新建一个index.ejs文件：</p>
<h4 id="templates-index-ejs"><a href="#templates-index-ejs" class="headerlink" title="templates/index.ejs"></a>templates/index.ejs</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"></div><div class="line"></div><div class="line">  </div><div class="line">  &lt;%= htmlWebpackPlugin.options.title %&gt;</div><div class="line"></div><div class="line"></div><div class="line">Welcome to New Page</div></pre></td></tr></table></figure>
<h3 id="修改-html-webpack-plugin-设置"><a href="#修改-html-webpack-plugin-设置" class="headerlink" title="修改 html-webpack-plugin 设置"></a>修改 html-webpack-plugin 设置</h3><p>修改<code>webpack.config.js</code>文件如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">plugins: [</div><div class="line">  <span class="keyword">new</span> HtmlwebpackPlugin(&#123;</div><div class="line">    title: <span class="string">'React Biolerplate by Linghucong'</span>,</div><div class="line">    template: path.resolve(__dirname, <span class="string">'templates/index.ejs'</span>),</div><div class="line">    inject: <span class="string">'body'</span></div><div class="line">  &#125;)</div><div class="line">]</div></pre></td></tr></table></figure></p>
<p>关于 html-webpack-plugin 更多高级用法可以<a href="https://github.com/ampedandwired/html-webpack-plugin" target="_blank" rel="external">参考其项目主页</a>。</p>
<h3 id="支持sourcemap"><a href="#支持sourcemap" class="headerlink" title="支持sourcemap"></a>支持sourcemap</h3><p>sourcemap的作用各位自行Google吧。要生成编译出的js文件的sourcemap文件，只需要在webpack配置文件中加入如下一行配置即可：<br><figure class="highlight groovy"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="string">devtool:</span> <span class="string">'source-map'</span>,</div></pre></td></tr></table></figure></p>
<p>运行<code>npm run build</code>可以看到一个会在<code>dist</code>目录生成一个新的文件<code>bundle.js.map</code>，这就是sourcemap文件。</p>
<h3 id="Minification-代码压缩"><a href="#Minification-代码压缩" class="headerlink" title="Minification 代码压缩"></a>Minification 代码压缩</h3><p>要对生成的js文件进行压缩，需要使用一个新的插件：UglifyJsPlugin。<br>修改<code>webpack.config.js</code>如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">......</div><div class="line">var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;</div><div class="line"></div><div class="line"><span class="keyword">var</span> config = &#123;</div><div class="line">......</div><div class="line">  plugins: [</div><div class="line">    ......</div><div class="line">    new UglifyJsPlugin(&#123; minimize: <span class="literal">true</span> &#125;)</div><div class="line">  ]</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="built_in">module</span>.exports = config;</div></pre></td></tr></table></figure>
<p>运行<code>npm run build</code>可以看到生成的bundle.js文件已经被minify了。</p>
<p>在实际的项目开发中，我们在开发阶段一般不需要将代码minify，因为压缩之后很不方便调试。因此，我们有必要将开发模式和发布模式区分开。我们通过设置<code>process.env.WEBPACK_ENV</code>来做区分。<br>修改<code>webpack.config.js</code>如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line">......</div><div class="line">var env = process.env.WEBPACK_ENV;</div><div class="line"><span class="keyword">var</span> outputFile;</div><div class="line"><span class="keyword">var</span> plugins = [<span class="keyword">new</span> HtmlwebpackPlugin(&#123;</div><div class="line">      title: <span class="string">'React Biolerplate by Linghucong'</span>,</div><div class="line">      template: path.resolve(__dirname, <span class="string">'templates/index.ejs'</span>),</div><div class="line">      inject: <span class="string">'body'</span></div><div class="line">    &#125;)];</div><div class="line"></div><div class="line"><span class="keyword">if</span> (env === <span class="string">'build'</span>) &#123;</div><div class="line">  <span class="keyword">var</span> UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;</div><div class="line">  plugins.push(<span class="keyword">new</span> UglifyJsPlugin(&#123; minimize: <span class="literal">true</span> &#125;));</div><div class="line">  outputFile = <span class="string">'bundle.min.js'</span>;</div><div class="line">&#125; <span class="keyword">else</span> &#123;  </div><div class="line">  outputFile = <span class="string">'bundle.js'</span>;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="keyword">var</span> config = &#123;</div><div class="line">......              </div><div class="line">  output: &#123;</div><div class="line">    path: path.resolve(__dirname, <span class="string">'dist'</span>),  </div><div class="line">    filename: outputFile</div><div class="line">  &#125;,</div><div class="line">......</div><div class="line">  plugins: plugins</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="built_in">module</span>.exports = config;</div></pre></td></tr></table></figure></p>
<p>同时需要修改npm run的快捷方式，在<code>package.json</code>文件中修改如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="string">"scripts"</span>: &#123;</div><div class="line">  <span class="string">"dev"</span>: <span class="string">"WEBPACK_ENV=dev webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist"</span>,</div><div class="line">  <span class="string">"build"</span>: <span class="string">"WEBPACK_ENV=build webpack"</span></div><div class="line">&#125;,</div></pre></td></tr></table></figure></p>
<h4 id="踩坑提醒-2"><a href="#踩坑提醒-2" class="headerlink" title="踩坑提醒"></a>踩坑提醒</h4><p>在Windows系统上不能像上述那样设置<code>WEBPACK_ENV</code>，可以使用<code>set</code>来设置，如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="string">"scripts"</span>: &#123;</div><div class="line">  <span class="string">"test"</span>: <span class="string">"mocha --compilers js:babel-register --require ./test/test_helper.js --recursive ./test"</span>,</div><div class="line">  <span class="string">"test:watch"</span>: <span class="string">"npm test -- --watch"</span>,</div><div class="line">  <span class="string">"dev"</span>: <span class="string">"set WEBPACK_ENV=dev&amp;&amp;webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist"</span>,</div><div class="line">  <span class="string">"build"</span>: <span class="string">"set WEBPACK_ENV=build&amp;&amp;webpack"</span></div><div class="line">&#125;,</div></pre></td></tr></table></figure>
<h3 id="更新项目代码"><a href="#更新项目代码" class="headerlink" title="更新项目代码"></a>更新项目代码</h3><p>对我们的组件稍作修改：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> <span class="string">'./index.less'</span>;</div><div class="line"></div><div class="line"><span class="keyword">import</span> component <span class="keyword">from</span> <span class="string">'./component'</span>;</div><div class="line"></div><div class="line"><span class="keyword">let</span> content = <span class="built_in">document</span>.getElementById(<span class="string">"content"</span>);</div><div class="line">content.appendChild(component());</div></pre></td></tr></table></figure></p>
<p>然后编译，运行：<br><figure class="highlight applescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">$ npm <span class="built_in">run</span> build</div><div class="line">$ npm <span class="built_in">run</span> dev</div></pre></td></tr></table></figure></p>
<p>可以看到，目前访问 <a href="http://localhost:3000/" target="_blank" rel="external">http://localhost:3000/</a> 的页面显示已经发生了变化。<br><img src="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/FhsJFMi-612vNsHQhDgwt8abvfKB814.jpg" alt="linghucong"></p>
<p>通过查看源代码，可以看到我们页面正是应用了我们的模板文件。</p>
<p><img src="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/FryFP8lTIrAosvDBBFT5h5nznmuH814.jpg" alt="source"></p>
<p>到目前为止的代码可以在<a href="https://github.com/jiji262/react_boilerplate/tree/master/_tutorial_/react_boilerplate_v3" target="_blank" rel="external">react_boilerplate _v3</a>中查看。</p>
<h2 id="创建React组件"><a href="#创建React组件" class="headerlink" title="创建React组件"></a>创建React组件</h2><p>我们将<code>app/index.js</code>修改一下，创建一个新的React组件。</p>
<h3 id="app-index-js-1"><a href="#app-index-js-1" class="headerlink" title="app/index.js"></a>app/index.js</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">'react'</span>;</div><div class="line"><span class="keyword">import</span> ReactDOM <span class="keyword">from</span> <span class="string">'react-dom'</span>;</div><div class="line"> </div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">HelloReact</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>&#123;</div><div class="line">  render() &#123;</div><div class="line">    <span class="keyword">return</span> Hello React!</div><div class="line">  &#125;</div><div class="line">&#125;</div><div class="line"> </div><div class="line">ReactDOM.render(, <span class="built_in">document</span>.getElementById(<span class="string">'content'</span>));</div></pre></td></tr></table></figure>
<p>代码十分简单，引入了<code>react</code>和<code>react-dom</code>，创建了一个叫做HelloReact的组件，并将其渲染到页面上id为<code>content</code>的DOM元素内。</p>
<h2 id="编译React代码"><a href="#编译React代码" class="headerlink" title="编译React代码"></a>编译React代码</h2><p>我们在之前已经在webpack的配置中配置好了对React的支持，因此目前不需要做什么修改了。</p>
<p><code>npm run build</code>之后就可以在页面上看到“Hello React!”了。</p>
<p>至此，我们基于ES6并使用webpack和Babel的React初始项目已经可以完美运行了。<br>到目前为止的代码可以在<a href="https://github.com/jiji262/react_boilerplate/tree/master/_tutorial_/react_boilerplate_v1" target="_blank" rel="external">react_boilerplate _v4</a>中查看。</p>
<h1 id="测试环境搭建（Mocha-Chai-Sinon）"><a href="#测试环境搭建（Mocha-Chai-Sinon）" class="headerlink" title="测试环境搭建（Mocha + Chai + Sinon）"></a>测试环境搭建（Mocha + Chai + Sinon）</h1><h2 id="所用技术介绍"><a href="#所用技术介绍" class="headerlink" title="所用技术介绍"></a>所用技术介绍</h2><p>如上所见，我在这里使用Mocha + Chai + Sinon 这几个技术来搭建我们的测试环境，简单介绍如下：</p>
<ul>
<li>Mocha：用于运行我们的测试用例。  </li>
<li>Chai：Mocha用的断言库。 </li>
<li><p>Sinon：用于创建一些mocks/stubs/spys。</p>
<p>另外值得一提的是，AirBnB创建了一个专门针对React代码测试的开源程序：Enzyme，有兴趣的可以研究一下。</p>
</li>
</ul>
<h2 id="Mocha安装及环境配置"><a href="#Mocha安装及环境配置" class="headerlink" title="Mocha安装及环境配置"></a>Mocha安装及环境配置</h2><h3 id="安装Mocha、Chai以及Sinon"><a href="#安装Mocha、Chai以及Sinon" class="headerlink" title="安装Mocha、Chai以及Sinon"></a>安装Mocha、Chai以及Sinon</h3><p>安装很简单，命令如下：<br><figure class="highlight q"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm i mocha chai sinon --<span class="built_in">save</span>-<span class="built_in">dev</span></div></pre></td></tr></table></figure></p>
<p>因为我们要支持ES6的语法，因此还需要安装一个额外的插件<code>babel-register</code>：</p>
<figure class="highlight q"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm i babel-register --<span class="built_in">save</span>-<span class="built_in">dev</span></div></pre></td></tr></table></figure>
<h3 id="写一个简单的测试用例"><a href="#写一个简单的测试用例" class="headerlink" title="写一个简单的测试用例"></a>写一个简单的测试用例</h3><p>Mocha默认会去当前目录下找test目录，然后在其中去找后缀为.js的文件。如果需要修改这个目录，可以使用Mocha的参数进行设置。<br>我们这里创建一个新的目录，叫做test，然后一个新的Spec文件：</p>
<h5 id="index-spec-js"><a href="#index-spec-js" class="headerlink" title="index.spec.js"></a>index.spec.js</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> &#123; expect &#125; <span class="keyword">from</span> <span class="string">'chai'</span>;</div><div class="line"></div><div class="line">describe(<span class="string">'hello react spec'</span>, () =&gt; &#123;</div><div class="line">  it(<span class="string">'works!'</span>, () =&gt; &#123;</div><div class="line">    expect(<span class="literal">true</span>).to.be.true;</div><div class="line">  &#125;);</div><div class="line">&#125;);</div></pre></td></tr></table></figure>
<p>这个时候我们在命令行中使用命令<code>mocha --compilers js:babel-register</code>运行mocha，如果顺利的话，可以看到如下结果：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">$ mocha --compilers js:babel-register</div><div class="line">  hello react spec</div><div class="line">    √ works!</div><div class="line">    </div><div class="line">  <span class="number">1</span> passing (<span class="number">11</span>ms)</div></pre></td></tr></table></figure>
<p>简单解释一下这里的<code>babel-register</code>。如果这里没有添加<code>--compilers</code>选项，则mocha会按照默认的方式执行，也就是“读取spec文件”-&gt;“运行测试用例”。使用了<code>babel-register</code>之后，则执行顺序为“读取spec文件”-&gt;“将ES6代码编译为ES5代码”-&gt;“运行测试用例”。</p>
<h4 id="踩坑提醒-3"><a href="#踩坑提醒-3" class="headerlink" title="踩坑提醒"></a>踩坑提醒</h4><p>如果执行<code>mocha --compilers js:babel-register</code>命令的时候，出现如下的错误：<br><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">$ mocha --compilers js:babel-register</div><div class="line">D:\node\react_boilerplate\test\index.spec.js:1</div><div class="line">(function (exports, require, module, __filename, __dirname) &#123; import &#123; expect &#125; from 'chai';</div><div class="line">                                                              ^^^^^^</div><div class="line">SyntaxError: Unexpected reserved word</div><div class="line">    at exports.runInThisContext (vm.js:53:16)</div><div class="line">    at Module._compile (module.js:373:25)</div><div class="line">    at loader (D:\node\react_boilerplate\node_modules\babel-register\lib\node.js:126:5)</div><div class="line">    at Object.require.extensions.(anonymous function) [as .js] (D:\node\react_boilerplate\node_modules\babel-register\lib\node.js:136:7)</div><div class="line">    at Module.load (module.js:343:32)</div><div class="line">    at Function.Module._load (module.js:300:12)</div><div class="line">    at Module.require (module.js:353:17)</div><div class="line">    at require (internal/module.js:12:17)</div><div class="line">    at C:\Users\i301792\AppData\Roaming\npm\node_modules\mocha\lib\mocha.js:219:27</div><div class="line">    at Array.forEach (native)</div><div class="line">    at Mocha.loadFiles (C:\Users\i301792\AppData\Roaming\npm\node_modules\mocha\lib\mocha.js:216:14)</div><div class="line">    at Mocha.run (C:\Users\i301792\AppData\Roaming\npm\node_modules\mocha\lib\mocha.js:468:10)</div><div class="line">    at Object. (C:\Users\i301792\AppData\Roaming\npm\node_modules\mocha\bin\_mocha:403:18)</div><div class="line">    at Module._compile (module.js:409:26)</div><div class="line">    at Object.Module._extensions..js (module.js:416:10)</div><div class="line">    at Module.load (module.js:343:32)</div><div class="line">    at Function.Module._load (module.js:300:12)</div><div class="line">    at Function.Module.runMain (module.js:441:10)</div><div class="line">    at startup (node.js:139:18)</div><div class="line">    at node.js:968:3</div></pre></td></tr></table></figure></p>
<p>这个错误可能是由于Babel的版本引入的。<a href="https://github.com/mochajs/mocha/issues/2054" target="_blank" rel="external">在这里</a>提供了一个解决方案：</p>
<p>在我们项目中创建一个.babelrc文件，其内容如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line">  <span class="string">"presets"</span>: [<span class="string">"react"</span>, <span class="string">"es2015"</span>]</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>其作用之前讲过了。现在就可以将我们<code>webpack.config.js</code>中对应设置删除了：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//webpack.config.js</span></div><div class="line">...</div><div class="line">      &#123; </div><div class="line">        test: <span class="regexp">/\.jsx?$/</span>, </div><div class="line">        loader: <span class="string">'babel'</span>, </div><div class="line">        exclude: <span class="regexp">/node_modules/</span></div><div class="line">      &#125;,</div></pre></td></tr></table></figure></p>
<h3 id="创建测试工具库test-helper-js"><a href="#创建测试工具库test-helper-js" class="headerlink" title="创建测试工具库test_helper.js"></a>创建测试工具库test_helper.js</h3><p>注意到我们在每个测试spec文件中，都会需要引入chai库的expect，这样就会有很多重复代码。当然还有其他一些通用的帮助性代码，因此我们需要一个库来集中进行管理。这里我们创建一个新的文件<code>/test/test_helper.js</code>:</p>
<h4 id="test-test-helper-js"><a href="#test-test-helper-js" class="headerlink" title="/test/test_helper.js"></a>/test/test_helper.js</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> &#123; expect &#125; <span class="keyword">from</span> <span class="string">'chai'</span>;</div><div class="line"><span class="keyword">import</span> sinon <span class="keyword">from</span> <span class="string">'sinon'</span>;</div><div class="line"></div><div class="line">global.expect = expect;</div><div class="line">global.sinon = sinon;</div></pre></td></tr></table></figure>
<p>在这里我只是添加了chai的expect，以及引入了sinon。</p>
<p>现在就可以将<code>index.spec.js</code>文件的第一行删除，然后通过如下的命令来执行mocha命令了：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mocha --compilers js:babel-register --<span class="built_in">require</span> ./test/test_helper.js --recursive</div></pre></td></tr></table></figure></p>
<p>执行结果如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">λ mocha --compilers js:babel-register --<span class="built_in">require</span> ./test/test_helper.js --recursive</div><div class="line">  hello react spec</div><div class="line">    √ works!</div><div class="line">  <span class="number">1</span> passing (<span class="number">12</span>ms)</div></pre></td></tr></table></figure>
<h3 id="配置package-json中的快捷方式"><a href="#配置package-json中的快捷方式" class="headerlink" title="配置package.json中的快捷方式"></a>配置<code>package.json</code>中的快捷方式</h3><p>在<code>package.json</code>中我们可以创建上述mocha命令的快捷方式。在<code>scripts</code>字段中作如下修改：</p>
<pre>
//package.json

  "scripts": {
    "test": "mocha --compilers js:babel-register --require ./test/test_helper.js --recursive ./test",
    "test:watch": "npm test -- --watch",
    "dev": "webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist",
    "build": "webpack"
  },
</pre>

<p>然后就可以使用<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm <span class="keyword">run</span> <span class="keyword">test</span></div></pre></td></tr></table></figure></p>
<p>来直接运行mocha了。</p>
<p>注意这里我还新增加了一个<code>npm run test:watch</code>快捷方式，其实就是使用了mocha的<code>--watch</code>选项。有了它，当我们在对代码进行修改的时候，就会自动运行test了。</p>
<p>到目前为止的代码可以在<a href="https://github.com/jiji262/react_boilerplate/tree/master/_tutorial_/react_boilerplate_v1" target="_blank" rel="external">react_boilerplate _v5</a>中查看。</p>
<h1 id="使用Karma测试"><a href="#使用Karma测试" class="headerlink" title="使用Karma测试"></a>使用Karma测试</h1><h2 id="karma安装与配置"><a href="#karma安装与配置" class="headerlink" title="karma安装与配置"></a>karma安装与配置</h2><p>Karma是一个基于Node.js的前端测试启动器（Test Runner），它出自Google的Angularjs团队。该工具可用于测试所有主流Web浏览器，可以支持Chrome、Safari、Firefox、IE、Opera甚至PhantomJS。</p>
<p>安装Karma：</p>
<figure class="highlight q"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm install karma --<span class="built_in">save</span>-<span class="built_in">dev</span></div></pre></td></tr></table></figure>
<p>然后还需要安装我们需要用到的一些依赖库：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">npm install lolex phantomjs-prebuilt phantomjs --save-dev</div><div class="line"></div><div class="line">npm install karma-chai karma-chai-plugins karma-chai-sinon karma-mocha karma-mocha-reporter karma-phantomjs-launcher karma-sinon karma-sinon-chai karma-sourcemap-loader karma-webpack --save-dev</div></pre></td></tr></table></figure></p>
<h3 id="踩坑提醒-4"><a href="#踩坑提醒-4" class="headerlink" title="踩坑提醒"></a>踩坑提醒</h3><p>不要问我为什么装那么多扩展，因为我踩过很多坑，这里就直接跳过了:&lt;</p>
<p>然后我们就可以使用karma命令来生成一个配置文件。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div></pre></td><td class="code"><pre><div class="line">λ .\node_modules\.bin\karma.cmd init karma.conf.js</div><div class="line"></div><div class="line">Which testing framework <span class="keyword">do</span> you want to use ?</div><div class="line">Press tab to list possible options. Enter to move to the next question.</div><div class="line">&gt; mocha</div><div class="line"></div><div class="line">Do you want to use Require.js ?</div><div class="line">This will add Require.js plugin.</div><div class="line">Press tab to list possible options. Enter to move to the next question.</div><div class="line">&gt; no</div><div class="line"></div><div class="line">Do you want to capture any browsers automatically ?</div><div class="line">Press tab to list possible options. Enter empty string to move to the next question.</div><div class="line">&gt; PhantomJS</div><div class="line">&gt; Chrome</div><div class="line">&gt;</div><div class="line"></div><div class="line">What is the location <span class="keyword">of</span> your source and test files ?</div><div class="line">You can use glob patterns, eg. <span class="string">"js/*.js"</span> or <span class="string">"test/**/*Spec.js"</span>.</div><div class="line">Enter empty string to move to the next question.</div><div class="line">&gt; app<span class="comment">/*.js</span></div><div class="line">&gt; test<span class="comment">/*.spec.js</span></div><div class="line">&gt;</div><div class="line"></div><div class="line">Should any of the files included by the previous patterns be excluded ?</div><div class="line">You can use glob patterns, eg. "**/*.swp".</div><div class="line">Enter empty string to move to the next question.</div><div class="line">&gt;</div><div class="line"></div><div class="line">Do you want Karma to watch all the files and run the tests on change ?</div><div class="line">Press tab to list possible options.</div><div class="line">&gt; yes</div><div class="line"></div><div class="line"></div><div class="line">Config file generated at "D:\node\react_boilerplate\karma.conf.js".</div></pre></td></tr></table></figure>
<p>然后我们就可以使用<code>karma start</code>命令来运行我们的测试用例了。不过现在直接运行可能还有一些问题，暂时先不管。</p>
<h2 id="优化Karma配置文件"><a href="#优化Karma配置文件" class="headerlink" title="优化Karma配置文件"></a>优化Karma配置文件</h2><p>我们使用一个单独的文件<code>test.webpack.js</code>来保存测试文件的路径，方便在karma设置中进行预处理。新建文件<code>test.webpack.js</code>如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">requireAll</span>(<span class="params">requireContext</span>) </span>&#123;</div><div class="line">  <span class="keyword">return</span> requireContext.keys().map(requireContext);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="keyword">var</span> modules = requireAll(<span class="built_in">require</span>.context(<span class="string">"./test"</span>, <span class="literal">true</span>, <span class="regexp">/.+\.spec\.jsx?$/</span>));</div><div class="line"></div><div class="line"><span class="built_in">module</span>.exports = modules</div></pre></td></tr></table></figure>
<p>然后修改<code>karma.config.js</code>:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> webpackConfig = <span class="built_in">require</span>(<span class="string">'./webpack.config'</span>);</div><div class="line">webpackConfig.devtool = <span class="string">'inline-source-map'</span>;</div><div class="line"></div><div class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span> (<span class="params">config</span>) </span>&#123;</div><div class="line">  config.set(&#123;</div><div class="line">    browsers: [ <span class="string">'PhantomJS'</span> ],</div><div class="line">    singleRun: <span class="literal">true</span>,</div><div class="line">    frameworks: [ <span class="string">'mocha'</span>, <span class="string">'chai'</span>, <span class="string">'sinon'</span>, <span class="string">'sinon-chai'</span> ],</div><div class="line">    files: [</div><div class="line">      <span class="string">'test.webpack.js'</span></div><div class="line">    ],</div><div class="line">    plugins: [</div><div class="line">      <span class="string">'karma-phantomjs-launcher'</span>,</div><div class="line">      <span class="string">'karma-chrome-launcher'</span>,</div><div class="line">      <span class="string">'karma-chai'</span>,</div><div class="line">      <span class="string">'karma-mocha'</span>,</div><div class="line">      <span class="string">'karma-sourcemap-loader'</span>,</div><div class="line">      <span class="string">'karma-webpack'</span>,</div><div class="line">      <span class="string">'karma-mocha-reporter'</span>,</div><div class="line">      <span class="string">'karma-sinon'</span>,</div><div class="line">      <span class="string">'karma-sinon-chai'</span></div><div class="line">    ],</div><div class="line">    preprocessors: &#123;</div><div class="line">      <span class="string">'test.webpack.js'</span>: [ <span class="string">'webpack'</span>, <span class="string">'sourcemap'</span> ]</div><div class="line">    &#125;,</div><div class="line">    reporters: [ <span class="string">'mocha'</span> ],</div><div class="line">    webpack: webpackConfig,</div><div class="line">    webpackServer: &#123;</div><div class="line">      noInfo: <span class="literal">true</span></div><div class="line">    &#125;,</div><div class="line">    autoWatch: <span class="literal">true</span></div><div class="line">  &#125;);</div><div class="line">&#125;;</div></pre></td></tr></table></figure></p>
<h2 id="运行Karma"><a href="#运行Karma" class="headerlink" title="运行Karma"></a>运行Karma</h2><p>好了，到现在为止，我们可以正常运行我们的测试用例了。使用命令<code>karma start</code>运行结果如下：</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">$ karma start</div><div class="line"></div><div class="line">START:</div><div class="line">29 04 2016 13:26:50.350:INFO [karma]: Karma v0.13.22 server started at http://localhost:9876/</div><div class="line">29 04 2016 13:26:50.375:INFO [launcher]: Starting browser PhantomJS</div><div class="line">29 04 2016 13:26:52.072:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket /#05AECTTMgBTkXK4kAAAA with id 76498752</div><div class="line">  hello react spec</div><div class="line">    √ works!!!</div><div class="line"></div><div class="line">Finished in 0.008 secs / 0.001 secs</div><div class="line"></div><div class="line">SUMMARY:</div><div class="line">√ 1 test completed</div></pre></td></tr></table></figure>
<p>可以看到，测试用例测试通过了。</p>
<p>目前我们在karma的配置文件中设置的浏览器类型是“browsers: [ ‘PhantomJS’ ]”，也就是会使用PhantomJS来运行。如果需要使用其他浏览器，可以做相应修改，甚至添加多个。比如我们要支持打开Chrome浏览器运行测试，修改如下：<br><figure class="highlight groovy"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="string">browsers:</span> [ <span class="string">'Chrome'</span> ]</div></pre></td></tr></table></figure></p>
<p>正常运作的前提是，必须事先安装好了对应的插件，对应Chrome的就是’karma-chrome-launcher’，其他浏览器类型类似处理。</p>
<h2 id="添加karma快捷方式到npm"><a href="#添加karma快捷方式到npm" class="headerlink" title="添加karma快捷方式到npm"></a>添加karma快捷方式到npm</h2><p>我们之前使用<code>npm run test</code>来运行测试，<code>npm run test:watch</code>来监听文件改变并运行测试。使用karma之后，需要在<code>package.json</code>中作如下修改：<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="string">"scripts"</span>: &#123;</div><div class="line">  <span class="string">"test"</span>: <span class="string">"karma start"</span>,</div><div class="line">  <span class="string">"test:watch"</span>: <span class="string">"watch \"</span>npm <span class="keyword">run</span> <span class="keyword">test</span>\<span class="string">" app/"</span>,</div><div class="line">  ......</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>另外需要安装一个npm包：<br><figure class="highlight q"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm install watch --<span class="built_in">save</span>-<span class="built_in">dev</span></div></pre></td></tr></table></figure></p>
<p>这样我们就可以使用<code>npm run test</code>来运行测试，<code>npm run test:watch</code>来监听文件改变并自动运行测试了：</p>
<p><img src="http://7xsxyo.com1.z0.glb.clouddn.com/2016/04/29/Fo8y7n8p4qhOi9Bq0gf3pXE-xrJQ87.jpg" alt="karma"></p>
<p>到目前为止我们自己的react boilerplate已经创建完毕了！代码可以在<a href="https://github.com/jiji262/react_boilerplate/tree/master/_tutorial_/react_boilerplate_v6" target="_blank" rel="external">react_boilerplate _v6</a>中查看。</p>
<h1 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h1><p>本文带你一步步建立了自己的react boilerplate项目，但是需要知道的是，文中所述甚浅，只是带你入门罢了。其中每一个话题，都可以展开来再写一系列的文章。比如测试所用的mocha+chai+sinon套装，比如React测试利器Enzyme等。即便是文中已经成型的代码，亦多有可优化的地方。如果你有好的意见或者建议，也欢迎到这个Github repo上来提pull request或者issue：</p>
<p><a href="https://github.com/jiji262/react_boilerplate" target="_blank" rel="external">https://github.com/jiji262/react_boilerplate</a></p>
<p>最后，感谢阅读。</p>
<h1 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h1><p><a href="http://blog.david-reid.com/2016/02/07/webpack-dev-server/" target="_blank" rel="external">Webpack Dev Server</a></p>
<p><a href="https://medium.com/learning-new-stuff/building-your-first-react-js-app-d53b0c98dc#.8bo5cmbs9" target="_blank" rel="external">Building Your First React.js App</a></p>
<p><a href="https://medium.com/@yamalight/building-modular-javascript-applications-in-es6-with-react-webpack-and-babel-538189cd485f" target="_blank" rel="external">Building modular javascript applications in ES6 with React, Webpack and Babel</a></p>
<p><a href="https://medium.com/@MoBinni/a-modern-isomorphic-stack-6609c7c9d057" target="_blank" rel="external">A Modern Isomorphic Stack</a></p>
<p><a href="http://jxnblk.com/writing/posts/static-site-generation-with-react-and-webpack/" target="_blank" rel="external">STATIC SITE GENERATION WITH REACT AND WEBPACK</a></p>
<p><a href="http://smashingboxes.com/blog/learn-react-part-1" target="_blank" rel="external">LEARN REACT.JS A LITTLE AT A TIME, PART 1</a></p>
<p><a href="https://www.twilio.com/blog/2015/08/setting-up-react-for-es6-with-webpack-and-babel-2.html" target="_blank" rel="external">Setting up React for ES6 with Webpack and Babel</a></p>
<p><a href="https://onsen.io/blog/mocha-chaijs-unit-test-coverage-es6/" target="_blank" rel="external">Mocha + Chai.js unit testing for ES6 with Istanbul code coverage</a></p>
<p><a href="https://github.com/davezuko/react-redux-starter-kit" target="_blank" rel="external">davezuko/react-redux-starter-kit</a></p>
<p><a href="https://github.com/jiji262/awesome-react-boilerplate" target="_blank" rel="external">awesome-react-boilerplate</a></p>

      
    </div>

    <div>
      
        
<div id="wechat_subscriber" style="display: block; padding: 10px 0; margin: 20px auto; width: 100%; text-align: center">
    <img id="wechat_subscriber_qcode" src="/uploads/wechatmp.jpg" alt="令狐葱 wechat" style="width: 200px; max-width: 100%;"/>
    <div>欢迎您扫一扫上面的二维码，订阅我的微信公众号！</div>
</div>


      
    </div>

    <div>
      
        
  <div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center;">
    <div></div>
    <button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
      <span>赏</span>
    </button>
    <div id="QR" style="display: none;">
      
        <div id="wechat" style="display: inline-block">
          <img id="wechat_qr" src="/uploads/wechatpay.png" alt="令狐葱 WeChat Pay"/>
          <p>微信打赏</p>
        </div>
      
      
        <div id="alipay" style="display: inline-block">
          <img id="alipay_qr" src="/uploads/alipaypay.png" alt="令狐葱 Alipay"/>
          <p>支付宝打赏</p>
        </div>
      
    </div>
  </div>


      
    </div>


    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/前端/" rel="tag"># 前端</a>
          
            <a href="/tags/webpack/" rel="tag"># webpack</a>
          
            <a href="/tags/react/" rel="tag"># react</a>
          
            <a href="/tags/karma/" rel="tag"># karma</a>
          
            <a href="/tags/mocha/" rel="tag"># mocha</a>
          
            <a href="/tags/sinon/" rel="tag"># sinon</a>
          
        </div>
      

      
        
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2016/04/25/2016-04-08-Javascript-IIFE/" rel="next" title="Javascript知识点：IIFE - 立即调用函数">
                <i class="fa fa-chevron-left"></i> Javascript知识点：IIFE - 立即调用函数
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2016/07/26/react-testing-with-karma-and-webpack-and-coverage-report/" rel="prev" title="手把手教你为React Boilerplate添加测试代码覆盖率报告">
                手把手教你为React Boilerplate添加测试代码覆盖率报告 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </article>



    <div class="post-spread">
      
        <!-- JiaThis Button BEGIN -->
<div class="jiathis_style">
  <a class="jiathis_button_tsina"></a>
  <a class="jiathis_button_tqq"></a>
  <a class="jiathis_button_weixin"></a>
  <a class="jiathis_button_cqq"></a>
  <a class="jiathis_button_douban"></a>
  <a class="jiathis_button_renren"></a>
  <a class="jiathis_button_qzone"></a>
  <a class="jiathis_button_kaixin001"></a>
  <a class="jiathis_button_copy"></a>
  <a href="http://www.jiathis.com/share" class="jiathis jiathis_txt jiathis_separator jtico jtico_jiathis" target="_blank"></a>
  <a class="jiathis_counter_style"></a>
</div>
<script type="text/javascript" >
  var jiathis_config={
    hideMore:false
  }
</script>
<script type="text/javascript" src="http://v3.jiathis.com/code/jia.js" charset="utf-8"></script>
<!-- JiaThis Button END -->

      
    </div>
  </div>

          
          </div>
          


          
  <div class="comments" id="comments">
    
      <div class="ds-thread" data-thread-key="2016/04/29/create-your-own-react-boilerplate/"
           data-title="手把手教你基于ES6架构自己的React Boilerplate项目" data-url="http://jiji262.github.io/2016/04/29/create-your-own-react-boilerplate/">
      </div>
    
  </div>


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/images/avatar.gif"
               alt="令狐葱" />
          <p class="site-author-name" itemprop="name">令狐葱</p>
           
              <p class="site-description motion-element" itemprop="description">去留无意，闲看庭前花开花落；宠辱不惊，漫随天外云卷云舒。</p>
          
        </div>
        <nav class="site-state motion-element">
        
          
            <div class="site-state-item site-state-posts">
              <a href="/">
                <span class="site-state-item-count">9</span>
                <span class="site-state-item-name">日志</span>
              </a>
            </div>
          

          

          
            <div class="site-state-item site-state-tags">
              <a href="/tags">
                <span class="site-state-item-count">28</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        

        <div class="links-of-author motion-element">
          
            
              <span class="links-of-author-item">
                <a href="https://github.com/jiji262" target="_blank" title="GitHub">
                  
                    <i class="fa fa-fw fa-github"></i>
                  
                  GitHub
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://twitter.com/linghucong" target="_blank" title="Twitter">
                  
                    <i class="fa fa-fw fa-twitter"></i>
                  
                  Twitter
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="http://weibo.com/jiji262" target="_blank" title="微博">
                  
                    <i class="fa fa-fw fa-globe"></i>
                  
                  微博
                </a>
              </span>
            
          
        </div>

        
        

        
        

        


      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#前言"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Update"><span class="nav-number">1.1.</span> <span class="nav-text">Update</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#代码"><span class="nav-number">1.2.</span> <span class="nav-text">代码</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#将使用的技术栈"><span class="nav-number">1.3.</span> <span class="nav-text">将使用的技术栈</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#webpack快速入门"><span class="nav-number">2.</span> <span class="nav-text">webpack快速入门</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#webpack介绍"><span class="nav-number">2.1.</span> <span class="nav-text">webpack介绍</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#安装配置webpack"><span class="nav-number">2.2.</span> <span class="nav-text">安装配置webpack</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#安装nodejs"><span class="nav-number">2.2.1.</span> <span class="nav-text">安装nodejs</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#初始化项目环境"><span class="nav-number">2.2.2.</span> <span class="nav-text">初始化项目环境</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#设置-gitignore"><span class="nav-number">2.2.3.</span> <span class="nav-text">设置.gitignore</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#安装webpack"><span class="nav-number">2.2.4.</span> <span class="nav-text">安装webpack</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#初始化项目结构和代码"><span class="nav-number">2.2.5.</span> <span class="nav-text">初始化项目结构和代码</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#app-component-js"><span class="nav-number">2.2.5.1.</span> <span class="nav-text">app/component.js</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#app-index-js"><span class="nav-number">2.2.5.2.</span> <span class="nav-text">app/index.js</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#配置webpack"><span class="nav-number">2.2.6.</span> <span class="nav-text">配置webpack</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#安装html-webpack-plugin"><span class="nav-number">2.2.7.</span> <span class="nav-text">安装html-webpack-plugin</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#dist-index-html"><span class="nav-number">2.2.7.1.</span> <span class="nav-text">dist/index.html</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#安装webpack-dev-server"><span class="nav-number">2.2.8.</span> <span class="nav-text">安装webpack-dev-server</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#处理CSS样式"><span class="nav-number">2.2.9.</span> <span class="nav-text">处理CSS样式</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#踩坑提醒"><span class="nav-number">2.2.9.1.</span> <span class="nav-text">踩坑提醒</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#webpack-支持ES6"><span class="nav-number">2.3.</span> <span class="nav-text">webpack 支持ES6</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Javascript包管理格式"><span class="nav-number">2.3.1.</span> <span class="nav-text">Javascript包管理格式</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#CommonJS"><span class="nav-number">2.3.1.1.</span> <span class="nav-text">CommonJS</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#AMD"><span class="nav-number">2.3.1.2.</span> <span class="nav-text">AMD</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#ES6"><span class="nav-number">2.3.1.3.</span> <span class="nav-text">ES6</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#webpack支持ES6语法"><span class="nav-number">2.3.2.</span> <span class="nav-text">webpack支持ES6语法</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#踩坑提醒-1"><span class="nav-number">2.3.2.1.</span> <span class="nav-text">踩坑提醒</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#在项目中支持使用React"><span class="nav-number">3.</span> <span class="nav-text">在项目中支持使用React</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#安装React"><span class="nav-number">3.1.</span> <span class="nav-text">安装React</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#改造项目结构"><span class="nav-number">3.2.</span> <span class="nav-text">改造项目结构</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#创建模板文件"><span class="nav-number">3.2.1.</span> <span class="nav-text">创建模板文件</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#templates-index-ejs"><span class="nav-number">3.2.1.1.</span> <span class="nav-text">templates/index.ejs</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#修改-html-webpack-plugin-设置"><span class="nav-number">3.2.2.</span> <span class="nav-text">修改 html-webpack-plugin 设置</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#支持sourcemap"><span class="nav-number">3.2.3.</span> <span class="nav-text">支持sourcemap</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Minification-代码压缩"><span class="nav-number">3.2.4.</span> <span class="nav-text">Minification 代码压缩</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#踩坑提醒-2"><span class="nav-number">3.2.4.1.</span> <span class="nav-text">踩坑提醒</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#更新项目代码"><span class="nav-number">3.2.5.</span> <span class="nav-text">更新项目代码</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#创建React组件"><span class="nav-number">3.3.</span> <span class="nav-text">创建React组件</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#app-index-js-1"><span class="nav-number">3.3.1.</span> <span class="nav-text">app/index.js</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#编译React代码"><span class="nav-number">3.4.</span> <span class="nav-text">编译React代码</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#测试环境搭建（Mocha-Chai-Sinon）"><span class="nav-number">4.</span> <span class="nav-text">测试环境搭建（Mocha + Chai + Sinon）</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#所用技术介绍"><span class="nav-number">4.1.</span> <span class="nav-text">所用技术介绍</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Mocha安装及环境配置"><span class="nav-number">4.2.</span> <span class="nav-text">Mocha安装及环境配置</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#安装Mocha、Chai以及Sinon"><span class="nav-number">4.2.1.</span> <span class="nav-text">安装Mocha、Chai以及Sinon</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#写一个简单的测试用例"><span class="nav-number">4.2.2.</span> <span class="nav-text">写一个简单的测试用例</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#index-spec-js"><span class="nav-number">4.2.2.0.1.</span> <span class="nav-text">index.spec.js</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#踩坑提醒-3"><span class="nav-number">4.2.2.1.</span> <span class="nav-text">踩坑提醒</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#创建测试工具库test-helper-js"><span class="nav-number">4.2.3.</span> <span class="nav-text">创建测试工具库test_helper.js</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#test-test-helper-js"><span class="nav-number">4.2.3.1.</span> <span class="nav-text">/test/test_helper.js</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#配置package-json中的快捷方式"><span class="nav-number">4.2.4.</span> <span class="nav-text">配置package.json中的快捷方式</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#使用Karma测试"><span class="nav-number">5.</span> <span class="nav-text">使用Karma测试</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#karma安装与配置"><span class="nav-number">5.1.</span> <span class="nav-text">karma安装与配置</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#踩坑提醒-4"><span class="nav-number">5.1.1.</span> <span class="nav-text">踩坑提醒</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#优化Karma配置文件"><span class="nav-number">5.2.</span> <span class="nav-text">优化Karma配置文件</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#运行Karma"><span class="nav-number">5.3.</span> <span class="nav-text">运行Karma</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#添加karma快捷方式到npm"><span class="nav-number">5.4.</span> <span class="nav-text">添加karma快捷方式到npm</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#后记"><span class="nav-number">6.</span> <span class="nav-text">后记</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#参考链接"><span class="nav-number">7.</span> <span class="nav-text">参考链接</span></a></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy;  2015 - 
  <span itemprop="copyrightYear">2017</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">令狐葱</span>
</div>


<div class="powered-by">
  由 <a class="theme-link" href="https://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Pisces
  </a>
</div>


        

        
      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
    </div>
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  




  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.0"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.0"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.0"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.0"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.0"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.0"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.0"></script>



  

  
    
  

  <script type="text/javascript">
    var duoshuoQuery = {short_name:"jiji262"};
    (function() {
      var ds = document.createElement('script');
      ds.type = 'text/javascript';ds.async = true;
      ds.id = 'duoshuo-script';
      ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
      ds.charset = 'UTF-8';
      (document.getElementsByTagName('head')[0]
      || document.getElementsByTagName('body')[0]).appendChild(ds);
    })();
  </script>

  
    
    
    <script src="/lib/ua-parser-js/dist/ua-parser.min.js?v=0.7.9"></script>
    <script src="/js/src/hook-duoshuo.js"></script>
  













  
  

  

  

  

  


</body>
</html>
